#include "Containers/MappedObject.h"
#include "catch.hpp"

TEST_CASE("Testing MappedObject", "[single-file]")
{
  class Derived : public MappedObject<Derived>
  {
  public:
    Derived(const std::string id) : MappedObject<Derived>(id) {}
  };

  const std::string name1{"MappedObject"};
  const std::string name2{"Derived1"};
  const std::string name3{"Derived2"};
  const std::string nonExistingName{"non-existing"};

  MappedObject<std::vector<Int_t>> object1(name1);

  Derived object2(name2);
  Derived object3(name3);

  SECTION("Testing GetInstance")
  {
    REQUIRE(MappedObject<std::vector<Int_t>>::GetInstance(name1) != nullptr);
    REQUIRE(MappedObject<std::vector<Int_t>>::GetInstance(nonExistingName) == nullptr);

    REQUIRE(Derived::GetInstance(name2) != nullptr);
    REQUIRE(Derived::GetInstance(name3) != nullptr);
    REQUIRE(Derived::GetInstance(nonExistingName) == nullptr);
  }

  SECTION("Testing GetNInstances")
  {
    REQUIRE(0 == MappedObject<std::string>::GetNInstances());
    REQUIRE(1 == MappedObject<std::vector<Int_t>>::GetNInstances());
    REQUIRE(2 == Derived::GetNInstances());
  }

  SECTION("Testing ~MappedObject (destruct)")
  {
    auto object = new Derived{"temporary"};
    REQUIRE(3 == Derived::GetNInstances());
    delete object;
    REQUIRE(2 == Derived::GetNInstances());
  }

  SECTION("Testing GetIdentifier")
  {
    REQUIRE(object1.GetIdentifier().compare(name1) == 0);
    REQUIRE(object1.GetIdentifier().compare(nonExistingName) != 0);
  }

  SECTION("Testing SetIdentifier")
  {
    std::string oldname{object2.GetIdentifier()};
    std::string newname{"newname"};
    object2.SetIdentifier(newname);

    REQUIRE(object2.GetIdentifier().compare(oldname) != 0);
    REQUIRE(object2.GetIdentifier().compare(newname) == 0);
    REQUIRE(Derived::GetNInstances() == 2);
  }

  const std::string name4{"Derived4"};
  Derived           object4(name4);

  SECTION("Testing iterator")
  {
    REQUIRE(Derived::IterIsEnd() == true);

    Derived::IterReset();

    REQUIRE(Derived::IterIsEnd() == false);
    REQUIRE(Derived::IterGetID().compare(name3) == 0);
    REQUIRE(Derived::IterGetObject() == Derived::GetInstance(name3));

    Derived::IterNext();

    REQUIRE(Derived::IterGetID().compare(name4) == 0);
    REQUIRE(Derived::IterGetObject() == Derived::GetInstance(name4));

    Derived::IterNext();

    REQUIRE(Derived::IterGetID().compare(name2) == 0);
    REQUIRE(Derived::IterGetObject() == Derived::GetInstance(name2));

    Derived::IterNext();

    REQUIRE(Derived::IterGetID().compare("") == 0);
    REQUIRE(Derived::IterGetObject() == nullptr);

    Derived::IterReset();

    REQUIRE(Derived::IterGetID().compare(name3) == 0);
    REQUIRE(Derived::IterGetObject() == Derived::GetInstance(name3));
  }
}